/** 
 * 项目名:shiro 
 * 文件名:RetryLimitHashedCredentialsMatcher.java 
 * 包名:com.spring.shiro.password 
 * 创建日期:2015年2月13日上午10:29:02 
 * 版权(c): ZTESOFT TECHNOLOGY CO.,LTD.Copyright 2012-2030.All rights reserved
 * 
*/  
  
package com.spring.shiro.password;  

import java.util.concurrent.atomic.AtomicInteger;

import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
 
/**
 * 密码重试次数限制<br>
 * <功能详细描述>
 * 如在1个小时内密码最多重试5次，如果尝试次数超过5次就锁定1小时，1小时后可再次重试，如果还是重试失败，可以锁定如1天，以此类推，防止密码被暴力破解。
 * 我们通过继承HashedCredentialsMatcher，且使用Ehcache记录重试次数和超时时间。
 * @author  chj_0507_dz@sina.com
 * @version [版本号,2015年2月13日]
 */
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

	private Ehcache passwordRetryCache;

	public RetryLimitHashedCredentialsMatcher() {
        CacheManager cacheManager = CacheManager.newInstance(CacheManager.class.getClassLoader().getResource("ehcache.xml"));
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		
		String username = (String)token.getPrincipal();
		
		Element element = passwordRetryCache.get(username);
		if (element == null) {
			element = new Element(username, new AtomicInteger(0));
			passwordRetryCache.put(element);
		}
		AtomicInteger retryCount = (AtomicInteger)element.getObjectValue();
		if (retryCount.incrementAndGet() > 5) {
			throw new ExcessiveAttemptsException();
		}
		
		boolean matches = super.doCredentialsMatch(token, info);
		if (matches) {
			passwordRetryCache.remove(username);
		}
		
		return matches;
	}
	
}
  